/*****************************************************************************
 *  ENTROPY - emerging network to reduce orwellian potency yield
 *
 *  Copyright (C) 2002 Juergen Buchmueller <pullmoll@stop1984.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software Foundation,
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 *	$Id: peer.h,v 1.15 2005/11/22 16:19:04 pullmoll Exp $
 *****************************************************************************/
#ifndef	_peer_h_
#define	_peer_h_

#include "osd.h"
#include "shmalloc.h"
#include "sock.h"
#include "crypt.h"
#include "bignum.h"
#include "key.h"
#include "uri.h"
#include "file.h"
#include "store.h"
#include "peermsg.h"
#include "ipv4_list.h"
#include "logger.h"

/*
 * Number of entries in a connection's queue.
 */
#ifndef	MSG_QUEUESIZE
#define	MSG_QUEUESIZE	16
#endif

/* number of entries in the global MSG_FEC queue */
#ifndef	FEC_QUEUESIZE
#define	FEC_QUEUESIZE	256
#endif

/* number of record keeping entries for successfully reconstructed fragments */
#define	FECSTATUSSIZE_LOG2 12
#define	FECSTATUSSIZE (1<<FECSTATUSSIZE_LOG2)

/*
 * A message entry in an outbound queue.
 * Data up to MSG_BUFFSIZE can be kept here,
 * otherwise the head of data matches the sha.diggest
 * and the data to be sent will come from a file.
 */

#define	MSG_BUFFSIZE	16384
typedef struct msg_entry_s {
	uint8_t htl;
	uint8_t cmd;
	sha1_digest_t sha1;
	size_t size;
	/* XXX: data is just MSG_BUFFSIZE, so only small packets will
	 * fit in here. If the data to be sent is longer, i.e. size
	 * greater than MSG_BUFFSIZE, then data[] contains a copy
	 * of he sha1 and the real data is fetched from the data
	 * store at the moment the message is to be sent
	 */
	uint8_t data[MSG_BUFFSIZE];
}	msg_entry_t;

/* only outbound connections have a queue; inbound have only size == 0 */
typedef struct msg_queue_s {
	size_t size;			/* size of the queue (MSG_QUEUESIZE or 0 inbound) */
	size_t head;			/* head of the queue */
	size_t tail;			/* tail of the queue */
	msg_entry_t entry[MSG_QUEUESIZE];
}	msg_queue_t;

/* inbound connections key counts */
typedef struct keycount_s {
	uint64_t total;
	uint64_t adv_count[16];
	uint64_t req_count[16];
	uint64_t ins_count[16];
	uint64_t fec_count[16];
	uint64_t fpr_count[16];
	uint64_t ann_count[16];
	uint64_t bcm_count[16];
}	keycount_t;

/* node announcement structure: address and crypto module */
#define	ANNOUNCE_MAX	256
typedef struct announce_s {
	struct sockaddr_in addr;	/* internet address and port */
	char module[32];			/* preferred crypto module */
	time_t last;				/* time when this entry was last announced */
}	announce_t;

/* node request history entry: key and time */
#define	REQUEST_MAX		4096
typedef struct request_s {
	sha1_digest_t sha1;
	time_t time;
}	request_t;

#define	FAILURE_MAX		(4*PEERS_MAX)
#define	BLOCKED_MAX		(4*PEERS_MAX)
#define	CONNECT_MAX		(4*PEERS_MAX)
typedef struct addr_time_s {
	struct sockaddr_in addr;	/* internet address and port */
	time_t time;				/* time until this address is blocked */
}	addr_time_t;

typedef struct stats_s {
	uint64_t adv_msgs;
	uint64_t adv_msgs_hit;
	uint64_t adv_msgs_ign;
	uint64_t adv_msgs_miss;
	uint64_t adv_msgs_fwd;
	uint64_t adv_total;
	uint64_t adv_second[60];
	uint64_t adv_minute[60];
	uint64_t adv_hour[24];
	uint64_t adv_24_hours;

	uint64_t req_msgs;
	uint64_t req_msgs_hit;
	uint64_t req_msgs_ign;
	uint64_t req_msgs_miss;
	uint64_t req_msgs_fwd;
	uint64_t req_total;
	uint64_t req_second[60];
	uint64_t req_minute[60];
	uint64_t req_hour[24];
	uint64_t req_24_hours;

	uint64_t ins_msgs;
	uint64_t ins_msgs_hit;
	uint64_t ins_msgs_ign;
	uint64_t ins_msgs_miss;
	uint64_t ins_msgs_fwd;
	uint64_t ins_msgs_bad;
	uint64_t ins_total;
	uint64_t ins_second[60];
	uint64_t ins_minute[60];
	uint64_t ins_hour[24];
	uint64_t ins_24_hours;

	uint64_t fec_msgs;
	uint64_t fec_msgs_hit;
	uint64_t fec_msgs_ign;
	uint64_t fec_msgs_miss;
	uint64_t fec_msgs_fwd;
	uint64_t fec_msgs_bad;
	uint64_t fec_total;
	uint64_t fec_second[60];
	uint64_t fec_minute[60];
	uint64_t fec_hour[24];
	uint64_t fec_24_hours;

	uint64_t fpr_msgs;
	uint64_t fpr_total;
	uint64_t fpr_second[60];
	uint64_t fpr_minute[60];
	uint64_t fpr_hour[24];
	uint64_t fpr_24_hours;

	uint64_t ann_msgs;
	uint64_t ann_total;
	uint64_t ann_second[60];
	uint64_t ann_minute[60];
	uint64_t ann_hour[24];
	uint64_t ann_24_hours;

	uint64_t bcm_msgs;
	uint64_t bcm_total;
	uint64_t bcm_second[60];
	uint64_t bcm_minute[60];
	uint64_t bcm_hour[24];
	uint64_t bcm_24_hours;
}	stats_t;

/* FEC request status and timeout */
typedef enum {
	FEC_UNUSED=0,
	FEC_PENDING,
	FEC_DONE,
	FEC_ERROR
}	fec_status_e;

typedef struct fec_status_s {
	sha1_digest_t sha1;			/* SHA1 hash of the requested fragment */
	int status;					/* current status of this MSG_FEC request */
	time_t time;				/* last time we worked down this request */
	size_t retry;				/* number of retries for this request */
}	fec_status_t;

/* a peer connection */
typedef struct peer_node_s {
	conn_t conn;				/* the connection */
	pid_t pid;					/* pid of the process using this peer slot */
	time_t start;				/* when did this connection start */
	size_t crypto_module_out;	/* crypto module index of outbound connection */
	size_t crypto_module_in;	/* crypto module index of inbound connection */
	void *crypto_ctx;			/* crypto module context (private data) */
	void *plaintext;			/* plain text message buffer */
	void *ciphertext;			/* cipher text message buffer */
	int cancer;					/* increment this if we receive bad packets */
	uint64_t storesize;		/* total size of the remote store */
	uint64_t currsize;			/* current size of the remote store */
	char type[31+1];			/* the node type, i.e. 'entropy' */
	uint32_t major;			/* the version of this peer */
	uint32_t minor;
	uint32_t build;
	uint8_t fingerprint[16];	/* the fingerprint for this node */
	stats_t stats;				/* connection statistics */
	keycount_t keycount;		/* keycounts for inbound connections */
	msg_queue_t queue;			/* message queue for outbound connections */
}	peer_node_t;

/* a queue entry for a MSG_FEC */
typedef struct fec_entry_s {
	time_t start;				/* time when this message was received */
	int htl;					/* hops to live of the message */
	sha1_digest_t sha1[1 + 12];	/* the fragment and 12 chunk digests */
	sha1_digest_t req;			/* hash of the 13 hashes (request key) */
}	fec_entry_t;

/* a MSG_FEC queue */
typedef struct fec_queue_s {
	size_t size;
	size_t head;
	size_t tail;
	fec_entry_t entry[FEC_QUEUESIZE];
}	fec_queue_t;

#define	MIN_MSGSIZE	(4+1+1+SHA1SIZE+4)
#define	MAX_MSGSIZE	(MIN_MSGSIZE+CHUNKSIZE)

typedef struct bandwidth_s {
	uint32_t limit;		/* bandiwdth limit; updated TICKS_PER_SEC */
	uint32_t used[60];		/* used up bandwidth per second (1 minute) */
	uint32_t average;		/* average bandwidth; updated once per second */
	uint32_t peak;			/* peak bandwidth; updated once per second */
	uint32_t estimated;	/* estimated possible bandwidth */
	uint32_t available;	/* estimated - average; updated once per second */
	uint64_t total;		/* total byte count */
	uint64_t daily;		/* daily byte count */
}	bandwidth_t;

#define	MAXCHANNEL	32
#define	MAXSENDER	32
#define	MAXPAYLOAD	(1024-4-20-4-32-32)	/* align to 1K */
#define	BROADCAST_MAX	512

typedef struct broadcast_msg_s {
	int id;
	sha1_digest_t sha1;
	time_t t0;
	char channel[MAXCHANNEL];
	char sender[MAXSENDER];
	char payload[MAXPAYLOAD];
}	broadcast_msg_t;

/* shared memory structure for all peers */
typedef struct peer_s {
	osd_sem_t sem_global;	/* semaphore to lock peer add/remove */
	osd_sem_t sem_bwlimit;	/* semaphore for the bandwidth limiting */
	osd_sem_t sem_stats;	/* semaphore to lock stats during updates */
	osd_sem_t sem_fec;		/* semaphore to lock fec stats & queue */
	osd_sem_t sem_bcm;		/* semaphore to lock broadcast ring buffer */
	bandwidth_t in;		/* current, used and average inbound bandwidth */
	bandwidth_t out;	/* current, used and average outbound bandwidth */
	size_t search;		/* peer_node_search() start index */
	size_t peercnt_in;	/* total number of inbound peers */
	size_t peercnt_out;	/* total number of outbound peers */
	/* inbound peers */
	peer_node_t *peers_in[PEERS_IN_MAX];
	peer_node_t *peers_out[PEERS_OUT_MAX];
	/* global routing over all peers */
	size_t routing_cnt;
	uint8_t routing[NUM_ROUTES];
	/* blocked peers */
	size_t blocked_cnt;
	addr_time_t blocked[BLOCKED_MAX];
	/* recent failures */
	size_t failure_cnt;
	addr_time_t failure[FAILURE_MAX];
	/* current pending connects */
	size_t connect_cnt;
	addr_time_t connect[CONNECT_MAX];
	/* asynchronous MSG_FEC queue */
	fec_queue_t fec_queue;
	/* status of MSG_FEC requests */
	fec_status_t fec[FECSTATUSSIZE];
	/* round-robin index for requested keys */
	size_t request_rr;
	/* history of requested keys */
	request_t req[REQUEST_MAX];
	/* round-robin index for inserting new announcements */
	size_t announce_in;
	/* round-robin index for finding new announcements */
	size_t announce_out;
	/* node announcements */
	announce_t ann[ANNOUNCE_MAX];
	size_t bcm_head;
	size_t bcm_tail;
	size_t bcm_count;
	broadcast_msg_t bcm[BROADCAST_MAX];
}	peer_t;

/* a peer info structure (used by the proxy) */
typedef struct peer_info_s {
	uint64_t in_total;			/* total input to our node */
	uint64_t out_total;		/* total output from our node */
	uint64_t in_daily;			/* daily input to our node */
	uint64_t out_daily;		/* daily output from our node */
	int active;
	int status;					/* from conn.status */
	char type[31+1];			/* node type, i.e. 'entropy' */
	uint32_t major;			/* peer version as reported on connect */
	uint32_t minor;
	uint32_t build;
	size_t crypto_module_out;
	size_t crypto_module_in;
	struct sockaddr_in address;
	char peername[MAXPATHLEN];
	time_t start;
	time_t last_io;
	uint64_t in_peer;			/* total input from this peer */
	uint64_t out_peer;			/* total output to this peer */
	uint8_t fingerprint[16];
	uint64_t storesize;
	uint64_t currsize;
	stats_t stats;
	keycount_t keycount;
	msg_queue_t queue;
}	peer_info_t;

/* a peer load structure (used by the client.c code for NodeInfo) */
typedef struct peer_load_s {
	int estimated_load;		/* estimated load in percent */
	int active_jobs;
	int avail_threads;
	int routing_time;
}	peer_load_t;

#ifdef	__cplusplus
extern "C" {
#endif

extern peer_t *g_peer;

int peer_info(size_t n, peer_info_t *info);
int peer_load(peer_load_t *pl);
int peer_in_count(void);
int peer_out_count(void);
int peer_adv_wait(sha1_digest_t *s, size_t count, int *pflags, int htl);
int peer_req_wait(sha1_digest_t *s, size_t count, int *pflags, int htl,
	uint8_t *buff);
int peer_ins_wait(sha1_digest_t *s, size_t count, int *pflags, int htl,
	uint8_t *buff);
int peer_adv_key(sha1_digest_t *s, int try, int htl, size_t *adv, int local);
int peer_req_key(sha1_digest_t *s, int try, int htl, size_t *req, int local);
int peer_ins_key(sha1_digest_t *s, int try, int htl, size_t *ins,
	size_t size, uint8_t *buff, int local);
int peer_req_fec(sha1_digest_t *s, int try, int htl, size_t *ins, int local);

int peer_ins_broadcast(const char *channel, const char *sender, const char *payload, int htl);
int peer_get_broadcast(int id, int *pmin, int *pmax,
	sha1_digest_t *pd, time_t *pt,
	char *channel, char *sender, char *payload);

int peer(void);

#ifdef	__cplusplus
}
#endif
#endif	/* !defined(_peer_h_) */
